package com.nbcio.cd.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.nbcio.cd.enums.FileTypeEnum;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 云网盘文件工具类
 *
 * @author nbacheng
 */
@Slf4j
public class CdFileUtils {

    /**
     * 获取文件扩展名
     *
     * @param fileName 文件名
     * @return 扩展名
     */
    public static String getFileExtension(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return "";
        }
        
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
            return "";
        }
        
        return fileName.substring(lastDotIndex + 1).toLowerCase();
    }

    /**
     * 获取文件名（不含扩展名）
     *
     * @param fileName 文件名
     * @return 文件名
     */
    public static String getFileNameWithoutExtension(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return "";
        }
        
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return fileName;
        }
        
        return fileName.substring(0, lastDotIndex);
    }

    /**
     * 格式化文件大小
     *
     * @param size 文件大小（字节）
     * @return 格式化后的大小
     */
    public static String formatFileSize(Long size) {
        if (size == null || size <= 0) {
            return "0 B";
        }
        
        String[] units = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex = 0;
        double fileSize = size.doubleValue();
        
        while (fileSize >= 1024 && unitIndex < units.length - 1) {
            fileSize /= 1024;
            unitIndex++;
        }
        
        return String.format("%.2f %s", fileSize, units[unitIndex]);
    }

    /**
     * 计算文件MD5哈希值
     *
     * @param file 文件
     * @return MD5哈希值
     */
    public static String calculateFileHash(File file) {
        try {
            return DigestUtil.md5Hex(file);
        } catch (Exception e) {
            log.error("计算文件MD5哈希值失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 计算文件MD5哈希值
     *
     * @param inputStream 输入流
     * @return MD5哈希值
     */
    public static String calculateFileHash(InputStream inputStream) {
        try {
            return DigestUtil.md5Hex(inputStream);
        } catch (Exception e) {
            log.error("计算文件MD5哈希值失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 根据文件扩展名获取文件类型
     *
     * @param fileName 文件名
     * @return 文件类型
     */
    public static FileTypeEnum getFileType(String fileName) {
        String extension = getFileExtension(fileName);
        return FileTypeEnum.getByExtension(extension);
    }

    /**
     * 检查文件是否可预览
     *
     * @param fileName 文件名
     * @return 是否可预览
     */
    public static boolean canPreview(String fileName) {
        FileTypeEnum fileType = getFileType(fileName);
        return fileType == FileTypeEnum.IMAGE || 
               fileType == FileTypeEnum.DOCUMENT || 
               fileType == FileTypeEnum.VIDEO;
    }

    /**
     * 检查文件是否为图片
     *
     * @param fileName 文件名
     * @return 是否为图片
     */
    public static boolean isImage(String fileName) {
        return getFileType(fileName) == FileTypeEnum.IMAGE;
    }

    /**
     * 检查文件是否为文档
     *
     * @param fileName 文件名
     * @return 是否为文档
     */
    public static boolean isDocument(String fileName) {
        return getFileType(fileName) == FileTypeEnum.DOCUMENT;
    }

    /**
     * 检查文件是否为视频
     *
     * @param fileName 文件名
     * @return 是否为视频
     */
    public static boolean isVideo(String fileName) {
        return getFileType(fileName) == FileTypeEnum.VIDEO;
    }

    /**
     * 检查文件是否为音频
     *
     * @param fileName 文件名
     * @return 是否为音频
     */
    public static boolean isAudio(String fileName) {
        return getFileType(fileName) == FileTypeEnum.AUDIO;
    }

    /**
     * 生成唯一文件名
     *
     * @param originalName 原始文件名
     * @return 唯一文件名
     */
    public static String generateUniqueFileName(String originalName) {
        String extension = getFileExtension(originalName);
        String nameWithoutExt = getFileNameWithoutExtension(originalName);
        long timestamp = System.currentTimeMillis();
        
        if (StrUtil.isNotBlank(extension)) {
            return String.format("%s_%d.%s", nameWithoutExt, timestamp, extension);
        } else {
            return String.format("%s_%d", nameWithoutExt, timestamp);
        }
    }

    /**
     * 检查文件路径是否安全
     *
     * @param path 文件路径
     * @return 是否安全
     */
    public static boolean isSafePath(String path) {
        if (StrUtil.isBlank(path)) {
            return false;
        }
        
        // 检查是否包含危险字符
        String[] dangerousChars = {"..", "~", "$", "&", "|", ";", "`", "(", ")", "<", ">", "\"", "'"};
        for (String dangerousChar : dangerousChars) {
            if (path.contains(dangerousChar)) {
                return false;
            }
        }
        
        return true;
    }

    /**
     * 创建目录
     *
     * @param dirPath 目录路径
     * @return 是否创建成功
     */
    public static boolean createDirectory(String dirPath) {
        try {
            Path path = Paths.get(dirPath);
            if (!Files.exists(path)) {
                Files.createDirectories(path);
            }
            return true;
        } catch (IOException e) {
            log.error("创建目录失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 删除文件
     *
     * @param filePath 文件路径
     * @return 是否删除成功
     */
    public static boolean deleteFile(String filePath) {
        try {
            File file = new File(filePath);
            if (file.exists()) {
                return file.delete();
            }
            return true;
        } catch (Exception e) {
            log.error("删除文件失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 检查文件是否存在
     *
     * @param filePath 文件路径
     * @return 是否存在
     */
    public static boolean fileExists(String filePath) {
        return FileUtil.exist(filePath);
    }

    /**
     * 获取文件MIME类型
     *
     * @param fileName 文件名
     * @return MIME类型
     */
    public static String getMimeType(String fileName) {
        try {
            Path path = Paths.get(fileName);
            return Files.probeContentType(path);
        } catch (Exception e) {
            log.error("获取文件MIME类型失败: {}", e.getMessage());
            return "application/octet-stream";
        }
    }
}
